home *** CD-ROM | disk | FTP | other *** search
/ Aminet 5 / Aminet 5 - March 1995.iso / Aminet / mus / edit / AlgoRhythms.lha / AlgoRhythms / Source / audio.c < prev    next >
C/C++ Source or Header  |  1994-11-25  |  45KB  |  1,393 lines

  1. /*
  2. ** Audio.C 
  3.     Copyright (c) 1993 by Thomas E. Janzen
  4.     All Rights Reserved
  5.  
  6.     THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
  7.     BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
  8.     CHANGES FOR FREE DISTRIBUTION.  NO TITLE TO AND OWNERSHIP OF THE
  9.     SOFTWARE IS HEREBY TRANSFERRED.  THOMAS E. JANZEN ASSUMES NO 
  10.     RESPONSIBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
  11.     
  12.     Thomas E. Janzen
  13.     208A Olde Derby Road
  14.     Norwood, MA  02062-1761
  15.     (617)769-7733
  16.     tej@world.std.com
  17.     
  18. **  FACILITY:
  19. **
  20. **    AlgoRhythms music improviser on Commodore (TM) Amiga (TM)
  21. **    compiled with SAS/C Amiga Compiler 6.50 
  22. **
  23. **  ABSTRACT:
  24. **
  25. **    audio.c contains functions for supporting internal Amiga audio.
  26. **
  27. **  AUTHORS: Thomas E. Janzen
  28. **
  29. **  CREATION DATE:    04-JUL-1993
  30. **
  31. **  MODIFICATION HISTORY:
  32. **    DATE    NAME    DESCRIPTION
  33. **   1 JAN 94 T. Janzen New for 3.0.
  34. */
  35. #define INTUI_V36_NAMES_ONLY
  36.  
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <math.h>
  40. #ifdef CLI
  41. #include <stdio.h>
  42. #endif
  43. #include <stdio.h>
  44. #include <limits.h>
  45. #include <exec/types.h>
  46. #include <exec/nodes.h>
  47. #include <exec/lists.h>
  48. #include <exec/ports.h>
  49. #include <exec/libraries.h>
  50. #include <exec/devices.h>
  51. #include <exec/io.h>
  52. #include <intuition/intuition.h>
  53. #include <libraries/gadtools.h>
  54. #include <proto/dos.h>
  55. #include <proto/graphics.h>
  56. #include <proto/exec.h>
  57. #include <proto/mathffp.h>
  58. #include <proto/intuition.h>
  59. #include <proto/gadtools.h>
  60. #include <exec/memory.h>
  61. #include <devices/audio.h>
  62. #include <dos/dosextens.h>
  63. #include <graphics/gfxbase.h>
  64. #include <libraries/dos.h>
  65. #include <libraries/iffparse.h>
  66. #include <proto/iffparse.h>
  67. #include <clib/iffparse_protos.h>
  68. #include <clib/exec_protos.h>
  69. #include <clib/alib_protos.h>
  70. #include <clib/dos_protos.h>
  71. #include <clib/iffparse_protos.h>
  72. #include <clib/graphics_protos.h>
  73. #include <iff/8svx.h>
  74. #include <iff/8svxapp.h>
  75. #include <exec/errors.h>
  76. #include <Libraries/asl.h> /* asl */
  77. #include <proto/asl.h>     /* asl */
  78.  
  79. #include "Window.h"
  80. #include "AlgoRhythms.h"
  81. #include "audio.h"
  82. #include "Record.h"
  83.  
  84. #define C_NOTES_PER_OCTAVE (12)
  85. #define C_OCTAVES_QTY (11)
  86. #define C_NOTES_TOTAL (C_NOTES_PER_OCTAVE * C_OCTAVES_QTY)
  87. #define C_LOW_C (16.3516 / 2.0)
  88. #define C_AUDIO_QTY (4)
  89. #define C_INSTR_QTY (17)  /* 17 is the default voice */
  90. #define C_DFLT_AUDIO (C_INSTR_QTY - 1)  /* 17 is the default voice */
  91. #define C_ONESHOT_SAMP (4)
  92. #define C_REPEAT_SAMP (4)
  93. #define C_TYP_OCTAVES (5)
  94. #define MINARGS (2)
  95. #define ID_CHAN MakeID('C', 'H', 'A', 'N')
  96. #define RIGHT (4)
  97. #define LEFT (2)
  98. #define BOTH (RIGHT | LEFT)
  99. #define C_CHUNKS_QTY (8)
  100. #define M_CHAN0_R (1 << 0)
  101. #define M_CHAN1_L (1 << 1)
  102. #define M_CHAN2_L (1 << 2)
  103. #define M_CHAN3_R (1 << 3)
  104. #define C_INST_NAME_LEN (56L)
  105. #define GAD_BUTTON_1    (16L)
  106. #define GAD_BUTTON_2    (17L)
  107. #define GAD_BUTTON_3    (18L)
  108. #define GAD_BUTTON_4    (19L)
  109. #define GAD_BUTTON_5    (20L)
  110. #define GAD_BUTTON_6    (21L)
  111. #define GAD_BUTTON_7    (22L)
  112. #define GAD_BUTTON_8    (23L)
  113. #define GAD_BUTTON_9    (24L)
  114. #define GAD_BUTTON_10   (25L)
  115. #define GAD_BUTTON_11   (26L)
  116. #define GAD_BUTTON_12   (27L)
  117. #define GAD_BUTTON_13   (28L)
  118. #define GAD_BUTTON_14   (29L)
  119. #define GAD_BUTTON_15   (30L)
  120. #define GAD_BUTTON_16   (31L)
  121. #define GAD_LAST        (32L)
  122. #define C_API_QUIET     (1)
  123. #define C_API_PLAYING   (2)
  124. #define C_OWNER_ME (1)
  125. #define C_OWNER_THEM (2)
  126. #define T_DFLT_NAME "DEFAULT SAWTOOTH"
  127.  
  128. static const channels_ary[C_AUDIO_QTY] 
  129.     = {M_CHAN0_R, M_CHAN1_L, M_CHAN2_L, M_CHAN3_R};
  130.  
  131. static struct Window *orch_wind = NULL;
  132. static struct Gadget *glist = NULL, 
  133.                      *orch_gads[GAD_LAST];
  134. ULONG orch_mask = 0;
  135.  
  136. #ifndef CLI
  137. static struct Gadget *create_orch_gadgets(UWORD topborder);
  138. #endif
  139.  
  140. static void calculate_frequency_table(double []);
  141. static void init_audio_instruments(void);
  142.  
  143. static UBYTE  whichannel[]= {(UBYTE) M_CHAN0_R, (UBYTE) M_CHAN1_L, 
  144.                             (UBYTE) M_CHAN2_L, (UBYTE) M_CHAN3_R};
  145. static struct EightSVXInfo svx_info[C_INSTR_QTY];
  146. static double frequency_table[C_NOTES_TOTAL];
  147. static void de_init_audio_instruments(void);
  148.  
  149. static const unsigned int   middle_c_num    = 60L,
  150.                             clock_ntsc      = 3579545L,  
  151.                             clock_pal       = 3546895L,
  152.                             step_ideal      = 1000L;
  153. static struct MsgPort *audio_msg_port;
  154. static struct Message *AudioMSG;
  155. static struct IOAudio *aud_open;
  156. static BYTE audio_device;
  157. static unsigned int main_clock;
  158.  
  159. static char orch_str[C_INSTR_QTY][C_INST_NAME_LEN]
  160.     = {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
  161.  
  162. typedef struct audio_port_io AUDIO_PORT_IO_TYPE;
  163. struct audio_port_io
  164. {
  165.     struct IOAudio  *api_aud_alloc,
  166.                     *api_aud_os,
  167.                     *api_aud_rep,
  168.                     *api_aud_free,
  169.                     *api_aud_finish; /* could use ADIOF_SYNCCYCLE but it 
  170.                                      ** wouldn't work well with 
  171.                                      ** long one-shots */
  172.     struct MsgPort  *api_port;
  173.     int api_status,
  174.         api_key; /* allocation key */ 
  175. };
  176.  
  177. static AUDIO_PORT_IO_TYPE voices_aud[C_AUDIO_QTY];
  178.  
  179. void init_audio(void)
  180. {
  181.     auto int ctr;
  182.     
  183.     audio_msg_port = CreateMsgPort();
  184.     if (NULL == audio_msg_port)
  185.     {
  186.         gi_fubar = TRUE;
  187.     }
  188.     aud_open = (struct IOAudio *)AllocMem(sizeof(struct IOAudio), 
  189.                 MEMF_PUBLIC | MEMF_CLEAR);
  190.     if (NULL == aud_open)
  191.     {
  192.         gi_fubar = TRUE;
  193.     }
  194.     aud_open->ioa_Request.io_Message.mn_ReplyPort  = audio_msg_port;
  195.     aud_open->ioa_Request.io_Message.mn_Node.ln_Pri= 0;
  196.     aud_open->ioa_Request.io_Command  = (UWORD)ADCMD_ALLOCATE;
  197.     aud_open->ioa_Request.io_Flags    = (UBYTE)ADIOF_NOWAIT;
  198.     aud_open->ioa_AllocKey            = (WORD) 0;
  199.     aud_open->ioa_Data                = whichannel;
  200.     aud_open->ioa_Length              = 0; /* open always succeeds with
  201.                                            ** zero data length; no channels
  202.                                            ** are allocated.
  203.                                            */
  204.     /* ioa_Length is a ULONG */
  205.     audio_device 
  206.         = OpenDevice(AUDIONAME, 0UL, (struct IORequest *) aud_open, 0L);
  207.         if (audio_device != 0)
  208.     {
  209.         gi_fubar = TRUE;
  210.     }
  211.     for (ctr = 0; ctr < C_AUDIO_QTY; ctr++)
  212.     {
  213.         /*
  214.         ** Allocate public memory for the IOAudio structures.
  215.         */
  216.         voices_aud[ctr].api_aud_alloc = 
  217.             (struct IOAudio *)AllocMem(sizeof(struct IOAudio), 
  218.             MEMF_PUBLIC /* | MEMF_CLEAR */);
  219.         if (NULL == voices_aud[ctr].api_aud_alloc)
  220.         {
  221.             gi_fubar = 1;
  222.             break;
  223.         }
  224.         voices_aud[ctr].api_aud_os = 
  225.             (struct IOAudio *)AllocMem(sizeof(struct IOAudio), 
  226.             MEMF_PUBLIC /* | MEMF_CLEAR */);
  227.         if (NULL == voices_aud[ctr].api_aud_os)
  228.         {
  229.             gi_fubar = 1;
  230.             break;
  231.         }
  232.         voices_aud[ctr].api_aud_rep = 
  233.             (struct IOAudio *)AllocMem(sizeof(struct IOAudio), 
  234.             MEMF_PUBLIC /* | MEMF_CLEAR */);
  235.         if (NULL == voices_aud[ctr].api_aud_rep)
  236.         {
  237.             gi_fubar = 1;
  238.             break;
  239.         }
  240.         voices_aud[ctr].api_aud_free = 
  241.             (struct IOAudio *)AllocMem(sizeof(struct IOAudio), 
  242.             MEMF_PUBLIC /* | MEMF_CLEAR */);
  243.         if (NULL == voices_aud[ctr].api_aud_free)
  244.         {
  245.             gi_fubar = 1;
  246.             break;
  247.         }
  248.         voices_aud[ctr].api_aud_finish = 
  249.             (struct IOAudio *)AllocMem(sizeof(struct IOAudio), 
  250.             MEMF_PUBLIC /* | MEMF_CLEAR */);
  251.         if (NULL == voices_aud[ctr].api_aud_finish)
  252.         {
  253.             gi_fubar = 1;
  254.             break;
  255.         }
  256.         voices_aud[ctr].api_port = CreateMsgPort();
  257.         if (NULL == voices_aud[ctr].api_port)
  258.         {
  259.             gi_fubar = 1;
  260.             break;
  261.         }
  262.  
  263.         /*
  264.         ** Initialize the allocate IOAudio struct
  265.         */
  266.         voices_aud[ctr].api_aud_alloc->ioa_Request.io_Command   
  267.             = (UWORD)ADCMD_ALLOCATE;
  268.         voices_aud[ctr].api_aud_alloc->ioa_Request.io_Flags 
  269.             = (UBYTE)ADIOF_NOWAIT;
  270.         voices_aud[ctr].api_aud_alloc->ioa_Request.io_Device 
  271.             = aud_open->ioa_Request.io_Device;
  272.         voices_aud[ctr].api_aud_alloc
  273.             ->ioa_Request.io_Message.mn_ReplyPort 
  274.             = voices_aud[ctr].api_port;
  275.         voices_aud[ctr].api_aud_alloc
  276.             ->ioa_Request.io_Message.mn_Node.ln_Pri = 50;
  277.         voices_aud[ctr].api_aud_alloc->ioa_Data = whichannel;
  278.         voices_aud[ctr].api_aud_alloc->ioa_Length = sizeof whichannel;
  279.  
  280.         /*
  281.         ** Initialize the one-shot IOAudio struct
  282.         */
  283.         voices_aud[ctr].api_aud_os->ioa_Request.io_Command
  284.             = (UWORD)CMD_WRITE;
  285.         voices_aud[ctr].api_aud_os->ioa_Request.io_Flags
  286.             = (UBYTE)ADIOF_PERVOL;
  287.         voices_aud[ctr].api_aud_os->ioa_Request.io_Device 
  288.             = aud_open->ioa_Request.io_Device;
  289.         voices_aud[ctr].api_aud_os->ioa_AllocKey 
  290.             = aud_open->ioa_AllocKey;
  291.         voices_aud[ctr].api_aud_os
  292.             ->ioa_Request.io_Message.mn_ReplyPort 
  293.             = voices_aud[ctr].api_port;
  294.         voices_aud[ctr].api_aud_os
  295.             ->ioa_Request.io_Message.mn_Node.ln_Pri = 50;
  296.         voices_aud[ctr].api_aud_os->ioa_Cycles = (UWORD) 1;
  297.  
  298.         /*
  299.         ** Initialize the repeating sound IOAudio struct
  300.         */
  301.         voices_aud[ctr].api_aud_rep->ioa_Request.io_Command 
  302.             = (UWORD)CMD_WRITE;
  303.         voices_aud[ctr].api_aud_rep->ioa_Request.io_Flags
  304.             = (UBYTE)ADIOF_PERVOL;
  305.         voices_aud[ctr].api_aud_rep->ioa_Request.io_Device 
  306.             = aud_open->ioa_Request.io_Device;
  307.         voices_aud[ctr].api_aud_rep->ioa_AllocKey 
  308.             = aud_open->ioa_AllocKey;
  309.         voices_aud[ctr].api_aud_rep
  310.             ->ioa_Request.io_Message.mn_ReplyPort 
  311.             = voices_aud[ctr].api_port;
  312.         voices_aud[ctr].api_aud_rep
  313.             ->ioa_Request.io_Message.mn_Node.ln_Pri = 50;
  314.         /*
  315.         ** Initialize the free IOAudio struct
  316.         */
  317.         voices_aud[ctr].api_aud_free->ioa_Request.io_Command 
  318.             = (UWORD)ADCMD_FREE;
  319.         voices_aud[ctr].api_aud_free->ioa_Request.io_Device 
  320.             = aud_open->ioa_Request.io_Device;
  321.         voices_aud[ctr].api_aud_free->ioa_AllocKey 
  322.             = aud_open->ioa_AllocKey;
  323.         voices_aud[ctr].api_aud_free
  324.             ->ioa_Request.io_Message.mn_ReplyPort 
  325.             = voices_aud[ctr].api_port;
  326.         voices_aud[ctr].api_aud_free
  327.             ->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  328.         /*
  329.         ** Initialize the finish IOAudio struct
  330.         */
  331.         voices_aud[ctr].api_aud_finish->ioa_Request.io_Command
  332.             = (UWORD)ADCMD_FINISH;
  333.         voices_aud[ctr].api_aud_finish->ioa_Request.io_Device
  334.             = aud_open->ioa_Request.io_Device;
  335.         voices_aud[ctr].api_aud_finish->ioa_AllocKey 
  336.             = aud_open->ioa_AllocKey;
  337.         voices_aud[ctr].api_aud_finish
  338.             ->ioa_Request.io_Message.mn_ReplyPort 
  339.             = voices_aud[ctr].api_port;
  340.         voices_aud[ctr].api_aud_finish
  341.             ->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  342.         /*
  343.         ** Initialize the status to quiet.
  344.         */
  345.         voices_aud[ctr].api_status = C_API_QUIET;
  346.     }
  347.     /*
  348.     ** Whether this is a PAL or NTSC system, use the correct clock rate for
  349.     ** calculating sample rates
  350.     */
  351.     if (GfxBase->DisplayFlags & PAL)
  352.     {
  353.         main_clock = clock_pal;
  354.     }
  355.     else
  356.     {
  357.         main_clock = clock_ntsc;
  358.     }
  359.     calculate_frequency_table(frequency_table);
  360.     init_audio_instruments();
  361.     if (NULL == (IFFParseBase = OpenLibrary("iffparse.library", 37L)))
  362.     {
  363.         gi_fubar = TRUE;
  364.     }
  365.     return;
  366. }
  367.  
  368. void de_init_audio(void)
  369. {
  370.     auto int ctr;
  371.     auto struct IOAudio *free_temp;
  372.  
  373.     de_init_audio_instruments();
  374.  
  375.     while ((AudioMSG = GetMsg(audio_msg_port)))
  376.     {
  377.         ;
  378.     }
  379.     for (ctr = 0; ctr < C_AUDIO_QTY; ctr++)
  380.     {
  381.         if (C_API_PLAYING == voices_aud[ctr].api_status)
  382.         {
  383.             free_temp = voices_aud[ctr].api_aud_free;
  384.             free_temp->ioa_Request.io_Flags = (UBYTE)IOF_QUICK;
  385.             /*
  386.             ** Will NOT reply if QUICK is set.
  387.             */
  388.             BeginIO((struct IORequest *) free_temp);
  389.             switch (free_temp->ioa_Request.io_Error)
  390.             {
  391.                 case 0:
  392.                     /* (free_temp->ioa_Request.io_Unit) = units freed */
  393.                     break; /* success */
  394.                 case ADIOERR_NOALLOCATION:
  395.                     break; /* mismatch of channel and allocation key */
  396.                 default:
  397.                     break;
  398.             }
  399.         }
  400.     }
  401.  
  402.     if (audio_msg_port != 0)
  403.     {   
  404.         DeleteMsgPort(audio_msg_port);
  405.     }
  406.     /*
  407.     ** Free channels before the Close
  408.     */
  409.     for (ctr = 0; ctr < C_AUDIO_QTY; ctr++)
  410.     {
  411.         FreeMem(voices_aud[ctr].api_aud_alloc, 
  412.             sizeof(struct IOAudio));
  413.         voices_aud[ctr].api_aud_alloc = NULL;
  414.  
  415.         FreeMem(voices_aud[ctr].api_aud_os, 
  416.             sizeof(struct IOAudio));
  417.         voices_aud[ctr].api_aud_os = NULL;
  418.  
  419.         FreeMem(voices_aud[ctr].api_aud_rep, 
  420.             sizeof(struct IOAudio));
  421.         voices_aud[ctr].api_aud_rep = NULL;
  422.  
  423.         FreeMem(voices_aud[ctr].api_aud_free, 
  424.             sizeof(struct IOAudio));
  425.         voices_aud[ctr].api_aud_free = NULL;
  426.  
  427.         FreeMem(voices_aud[ctr].api_aud_finish, 
  428.             sizeof(struct IOAudio));
  429.         voices_aud[ctr].api_aud_finish = NULL;
  430.  
  431.         DeleteMsgPort(voices_aud[ctr].api_port);
  432.     }
  433.     /*
  434.     ** Close the device
  435.     */
  436.     if (0 == audio_device)
  437.     { 
  438.         CloseDevice((struct IORequest *) aud_open);
  439.         /*
  440.         ** The close should set deivce to -1; 
  441.         ** io_Unit is map of channesl to free, unit should be 0
  442.         */
  443.     }
  444.     FreeMem(aud_open, sizeof(struct IOAudio));
  445.     aud_open = NULL;
  446.  
  447.     if (IFFParseBase)
  448.     {
  449.         CloseLibrary(IFFParseBase);
  450.     }
  451.     return;
  452. }
  453.  
  454. void play_audio_note(NOTE_EVENT_TYPE *play_event) 
  455. {
  456.  
  457.     /* Note that the finding of earliest event to pre-empt fails when
  458.     ** The number of events wraps around at 2^31 ! by stopping the wrong 
  459.     ** voice */
  460.     auto int  oct,
  461.               pitch,
  462.               volume,
  463.               audio_chan,
  464.               chair,
  465.               sample_rate,
  466.               total_samples,
  467.               repeat_samples,
  468.               no_repeat,
  469.               chan_ctr;
  470.     static double duration,
  471.                   frequency;
  472.     auto struct IOAudio *os_temp     = NULL,
  473.                         *rep_temp    = NULL,
  474.                         *alloc_temp  = NULL,
  475.                         *free_temp   = NULL,
  476.                         *finish_temp = NULL;
  477.     static int audio_index = 0; /* must be static to persist! */
  478.  
  479.     if (0 == play_event->nv_i_dynamic)
  480.     /* If this is a note turn-off */
  481.     {
  482.         audio_chan = play_event->nv_i_audio_chan;
  483.         /* Turn off the note */
  484.         finish_temp = voices_aud[audio_chan].api_aud_finish;
  485.         finish_temp = voices_aud[audio_chan].api_aud_finish;
  486.         finish_temp->ioa_Request.io_Flags 
  487.             = (UBYTE)0; /* won't reply port if IOF_QUICK is set */
  488.         finish_temp->ioa_AllocKey = voices_aud[audio_chan].api_key;
  489.         /* Tell the voice to finish */
  490.         /* It won't reply since IOF_QUICK is set; this is synchronous */
  491.         BeginIO((struct IORequest *) finish_temp);
  492.         while (0 == GetMsg(finish_temp->ioa_Request.io_Message
  493.                .mn_ReplyPort)) /*might be hanging here */
  494.         {
  495.             ;
  496.         }
  497.         switch (finish_temp->ioa_Request.io_Error)
  498.         {
  499.             case 0:
  500.                 /* free_temp->ioa_Request.io_Unit = units freed */
  501.                 break; /* success */
  502.             case ADIOERR_NOALLOCATION:
  503.                 play_event->nv_i_audio_chan = C_NO_CHAN;        
  504.                 play_event->nv_i_was_audio = 0;
  505.                 return;
  506.                 break; /* mismatch of channel and allocation key */
  507.             default:
  508.                 break;
  509.         }
  510.         /* Free the channel  */
  511.         free_temp = voices_aud[audio_chan].api_aud_free;
  512.         free_temp->ioa_Request.io_Flags = 0;
  513.         /*
  514.         ** Will NOT reply if QUICK is set.
  515.         */
  516.         BeginIO((struct IORequest *) free_temp);
  517.         while (0 == GetMsg(free_temp->ioa_Request.io_Message
  518.                .mn_ReplyPort)) /*might be hanging here */
  519.         {
  520.             ;
  521.         }
  522.         switch (free_temp->ioa_Request.io_Error)
  523.         {
  524.             case 0:
  525.                 /* free_temp->ioa_Request.io_Unit = units freed */
  526.                 break; /* success */
  527.             case ADIOERR_NOALLOCATION:
  528.                 break; /* mismatch of channel and allocation key */
  529.             default:
  530.                 break;
  531.         }
  532.         voices_aud[audio_chan].api_key = 0;
  533.         voices_aud[audio_chan].api_status = C_API_QUIET; 
  534.         play_event->nv_i_audio_chan = C_NO_CHAN;        
  535.         play_event->nv_i_was_audio = 0;
  536.         return;
  537.     }
  538.     play_event->nv_i_was_audio = 1;
  539.     /*
  540.     ** Try to find an unused voice first.
  541.     */
  542.     chan_ctr = 0;
  543.     while ((voices_aud[chan_ctr].api_status != C_API_QUIET) 
  544.         &&   (chan_ctr < C_AUDIO_QTY))
  545.     {
  546.         chan_ctr++;
  547.     }
  548.     if (chan_ctr >= C_AUDIO_QTY) 
  549.     {
  550.         audio_chan = audio_index;
  551.         /* then there was no free channel; all are playing now */
  552.         finish_temp = voices_aud[audio_chan].api_aud_finish;
  553.         finish_temp->ioa_Request.io_Flags = 0;
  554.         /* Tell the voice to finish */
  555.         /* It won't reply since IOF_QUICK is set; this is synchronous */
  556.         BeginIO((struct IORequest *) finish_temp);
  557.         while (0 == GetMsg(finish_temp->ioa_Request.io_Message
  558.                .mn_ReplyPort)) /*might be hanging here */
  559.         {
  560.             ;
  561.         }
  562.         switch (finish_temp->ioa_Request.io_Error)
  563.         {
  564.             case 0:
  565.                 /* free_temp->ioa_Request.io_Unit = units freed */
  566.                 break; /* success */
  567.             case ADIOERR_NOALLOCATION:
  568.                 break; /* mismatch of channel and allocation key */
  569.             default:
  570.                 break;
  571.         }
  572.  
  573.         free_temp = voices_aud[audio_chan].api_aud_free;
  574.         free_temp->ioa_Request.io_Flags = (UBYTE)0;
  575.         /*
  576.         ** Will NOT reply if QUICK is set.
  577.         */
  578.         BeginIO((struct IORequest *) free_temp);
  579.         while (0 == GetMsg(free_temp->ioa_Request.io_Message
  580.                .mn_ReplyPort)) /*might be hanging here */
  581.         {
  582.             ;
  583.         }
  584.         switch (free_temp->ioa_Request.io_Error)
  585.         {
  586.             case 0:
  587.                 /* free_temp->ioa_Request.io_Unit = units freed */
  588.                 break; /* success */
  589.             case ADIOERR_NOALLOCATION:
  590.                 break; /* mismatch of channel and allocation key */
  591.             default:
  592.                 break;
  593.         }
  594.     }
  595.     else /* chan_ctr is an index to a free channel */
  596.     {
  597.         audio_chan = chan_ctr;
  598.     }
  599.     /*
  600.     ** This approach to finding the audio voice must be replaced
  601.     ** by something that allows 16 chairs to use 4 audio voices.
  602.     ** It might be useful to know which voice was the last one running.
  603.     */
  604.  
  605.     os_temp     = voices_aud[audio_chan].api_aud_os;
  606.     rep_temp    = voices_aud[audio_chan].api_aud_rep;
  607.     alloc_temp  = voices_aud[audio_chan].api_aud_alloc;
  608.     finish_temp = voices_aud[audio_chan].api_aud_finish;
  609.     free_temp   = voices_aud[audio_chan].api_aud_free;
  610.     /*
  611.     ** do a checkio here
  612.     */
  613.     play_event->nv_i_audio_chan     = audio_chan;
  614.  
  615.     chair    = play_event->nv_i_channel;
  616.     pitch  = play_event->nv_i_cur_pitch;
  617.     duration    =  (double)play_event->nv_r_duration.tv_secs 
  618.                 + ((double)play_event->nv_r_duration.tv_micro
  619.                 / 1000000.0);
  620.     volume = play_event->nv_i_dynamic >> 1;
  621.     if ((pitch > C_NOTES_TOTAL) || (pitch < 0))
  622.     {
  623.         pitch = middle_c_num;
  624.     }
  625.     frequency = frequency_table[pitch];
  626.  
  627.     /*
  628.     ** ADCMD_ALLOCATE
  629.     **  synchronous if success and no locks to be stolen
  630.     **      or if it fails with no-wait flag set 
  631.     **  replies if IOF_QUICK is clear
  632.     ** otherwise is asynch and replies and clear IOF_QUICK
  633.     ** Since I set NOWAIT, it won't be synchronous, that is it won't
  634.     ** wait until channels can be stolen.
  635.     */
  636.     alloc_temp->ioa_Request.io_Flags = (UBYTE)(IOF_QUICK | ADIOF_NOWAIT);
  637.     alloc_temp->ioa_AllocKey = 0; 
  638.     BeginIO((struct IORequest *) alloc_temp);
  639.     switch (alloc_temp->ioa_Request.io_Error)
  640.     {
  641.         case 0:
  642.             break; /* successful */
  643.         case ADIOERR_ALLOCFAILED: /* manual said IOERR_ALLOCFAILED,
  644.                                   ** but no such code exists */
  645.             /* channels would have to have been stolen */
  646.             return;
  647.             break;
  648.         default:
  649.             break;
  650.     }
  651.     switch ((int)(alloc_temp->ioa_Request.io_Unit))
  652.     {
  653.         case 0:
  654.             break; /* successful */
  655.         default:
  656.             break;
  657.     }
  658.  
  659.     voices_aud[audio_chan].api_status = C_API_PLAYING;
  660.  
  661.     finish_temp->ioa_Request.io_Unit =
  662.     free_temp->ioa_Request.io_Unit =
  663.     os_temp->ioa_Request.io_Unit =
  664.     rep_temp->ioa_Request.io_Unit =
  665.     alloc_temp->ioa_Request.io_Unit;
  666.  
  667.     voices_aud[audio_chan].api_key =
  668.     finish_temp->ioa_AllocKey =
  669.     free_temp->ioa_AllocKey =
  670.     os_temp->ioa_AllocKey =
  671.     rep_temp->ioa_AllocKey =
  672.     alloc_temp->ioa_AllocKey;
  673.  
  674.     oct = svx_info[chair].Vhdr.ctOctave;
  675.     if (svx_info[chair].spcycs[0] > 0)
  676.     {
  677.         do
  678.         {
  679.             oct--;
  680.             rep_temp->ioa_Period = os_temp->ioa_Period 
  681.                 = (UWORD) (main_clock / ((int)floor(frequency) 
  682.                 * svx_info[chair].spcycs[oct]));
  683.         } while ((os_temp->ioa_Period < 124) && (oct > 0));
  684.         /* preferred periods for anti-aliasing 124 to 256 */
  685.     }
  686.     else
  687.     {
  688.         rep_temp->ioa_Period = os_temp->ioa_Period 
  689.             = (UWORD)(main_clock / svx_info[chair].Vhdr.samplesPerSec);
  690.         oct = 0;
  691.     }
  692. #ifdef MEASURE
  693.         if (play_event->nv_i_dynamic != 0)
  694.         {
  695.             gi_notes_measure++;
  696.         }
  697. #endif
  698.     sample_rate = main_clock / rep_temp->ioa_Period;
  699.     /*
  700.     ** Force total_samples even
  701.     */
  702.     total_samples = (int)((double)sample_rate * duration) & ~1;
  703.     /*
  704.     ** If there is a one-shot part
  705.     */
  706.     no_repeat = FALSE;
  707.     if (svx_info[chair].Vhdr.oneShotHiSamples > 0)
  708.     {
  709.         os_temp->ioa_Data = (BYTE *)(svx_info[chair].osamps[oct]);
  710.         if (total_samples > svx_info[chair].osizes[oct])
  711.         {
  712.             os_temp->ioa_Length = svx_info[chair].osizes[oct];
  713.             repeat_samples = (total_samples - os_temp->ioa_Length) & ~1;
  714.         }
  715.         else
  716.         {
  717.             os_temp->ioa_Length 
  718.                 = ((total_samples > 0) ? total_samples : 2);
  719.             no_repeat = TRUE;
  720.         }
  721.         os_temp->ioa_Volume = (UWORD) volume;
  722.         os_temp->ioa_Request.io_Flags |= (UBYTE)IOF_QUICK;
  723.         BeginIO((struct IORequest *) os_temp);
  724.         switch (os_temp->ioa_Request.io_Error)
  725.         {
  726.             case 0:
  727.                 ; /* successful; 
  728.                   ** there will be a reply at the start of the write; 
  729.                   ** quick should be clear 
  730.                   */
  731.                   if (os_temp->ioa_Request.io_Flags & (UBYTE)IOF_QUICK)
  732.                   { 
  733.                     /* was successful and will reply later */
  734.                     while (0 == GetMsg(os_temp->ioa_Request.io_Message
  735.                             .mn_ReplyPort)) /*might be hanging here */
  736.                     {
  737.                         os_temp = os_temp;
  738.                     }
  739.                   }
  740.                   break;
  741.             case IOERR_ABORTED:
  742.                 /* no-op */
  743.                 /* it was aborted or stolen; there won't be a sound.
  744.                 ** It won't reply because IOF_QUICK was set */
  745.                 break;
  746.             case ADIOERR_NOALLOCATION:
  747.                 break; /* mismatch of channel and allocation key */
  748.             default:
  749.                 break;
  750.         }
  751.     }
  752.     /*
  753.     ** If there is a repeat part to the sample
  754.     */
  755.     if ((svx_info[chair].Vhdr.repeatHiSamples > 0) && !no_repeat)
  756.     {
  757.         rep_temp->ioa_Volume = (UWORD) volume;
  758.         rep_temp->ioa_Data   = (BYTE *)(svx_info[chair].rsamps[oct]);
  759.         rep_temp->ioa_Cycles = (UWORD)((int)floor(frequency * duration) 
  760.             * svx_info[chair].spcycs[oct]
  761.             / svx_info[chair].rsizes[oct]);
  762.         if ((rep_temp->ioa_Cycles * svx_info[chair].rsizes[oct])
  763.             > repeat_samples)
  764.         {
  765.             rep_temp->ioa_Cycles = (UWORD)(repeat_samples 
  766.                 / svx_info[chair].spcycs[oct]);
  767.         }
  768.         if (0 == rep_temp->ioa_Cycles)
  769.         {
  770.             rep_temp->ioa_Cycles = (UWORD) 1;
  771.         }
  772.         rep_temp->ioa_Length = (ULONG) svx_info[chair].rsizes[oct];
  773.         rep_temp->ioa_Request.io_Flags |= (UBYTE)IOF_QUICK;
  774.         BeginIO((struct IORequest *) rep_temp);
  775.         switch (rep_temp->ioa_Request.io_Error)
  776.         {
  777.             case 0:
  778.                 ; /* successful; 
  779.                   ** there will be a reply at the start of the write; 
  780.                   ** quick should be clear 
  781.                   */
  782.                   if (rep_temp->ioa_Request.io_Flags & (UBYTE)IOF_QUICK)
  783.                   {
  784.                     while (0 == GetMsg(rep_temp->ioa_Request.io_Message
  785.                             .mn_ReplyPort))
  786.                     {
  787.                         ;
  788.                     }
  789.                     ; /* was successful and will reply later */
  790.                   }
  791.                   break;
  792.             case IOERR_ABORTED:
  793.                 ; /* it was aborted or stolen; there won't be a sound.
  794.                   ** It won't reply because IOF_QUICK was set */
  795.                     break;
  796.             case ADIOERR_NOALLOCATION:
  797.                 break; /* mismatch of channel and allocation key */
  798.             default:
  799.                 break;
  800.         }
  801.     }
  802.     audio_index = (audio_index + 1) % C_AUDIO_QTY;
  803.     return;
  804. }
  805.  
  806. static void calculate_frequency_table(double *frequency_table)
  807. {
  808.     static int  pitch,
  809.                 octave;
  810.  
  811.     for (octave = 0; octave < C_OCTAVES_QTY; octave++) 
  812.     {
  813.         for (pitch = 0; pitch < C_NOTES_PER_OCTAVE; pitch++) 
  814.         {
  815.             frequency_table[(octave * C_NOTES_PER_OCTAVE) + pitch] 
  816.                 = C_LOW_C 
  817.                 * pow2( ((double)(octave * C_NOTES_PER_OCTAVE) + pitch) 
  818.                 / 12.0);
  819.         }
  820.     }
  821.     return;
  822. }
  823.  
  824. static void init_audio_instruments(void)
  825. {
  826.     static int  octave,
  827.                 sample,
  828.                 instrument,
  829.                 harmonic;
  830.  
  831.     svx_info[C_DFLT_AUDIO].Vhdr.ctOctave           = C_TYP_OCTAVES;
  832.     svx_info[C_DFLT_AUDIO].Vhdr.samplesPerSec      = 0;
  833.     svx_info[C_DFLT_AUDIO].Vhdr.oneShotHiSamples   = C_ONESHOT_SAMP;
  834.     svx_info[C_DFLT_AUDIO].Vhdr.repeatHiSamples    =  C_REPEAT_SAMP;
  835.     svx_info[C_DFLT_AUDIO].Vhdr.samplesPerHiCycle  = C_ONESHOT_SAMP;
  836.     strncpy(svx_info[C_DFLT_AUDIO].name, "AlgoRhythms Default Tone", 
  837.         C_INST_NAME_LEN);
  838.     svx_info[C_DFLT_AUDIO].name[sizeof svx_info[C_DFLT_AUDIO].name - 1] 
  839.         = '\0';
  840.     svx_info[C_DFLT_AUDIO].Vhdr.volume = 0x0000FFFF;
  841.     for (octave = 0; octave < C_TYP_OCTAVES; octave++)
  842.     {
  843.         svx_info[C_DFLT_AUDIO].osizes[octave] 
  844.             = C_ONESHOT_SAMP * (int)floor(pow2( (double)octave));
  845.         svx_info[C_DFLT_AUDIO].osamps[octave]
  846.             = (BYTE *)AllocMem(svx_info[C_DFLT_AUDIO].osizes[octave], 
  847.             MEMF_CHIP | MEMF_PUBLIC);
  848.         if (svx_info[C_DFLT_AUDIO].osamps[octave] != NULL)
  849.         {
  850.             for (   sample = 0; 
  851.                     sample < svx_info[C_DFLT_AUDIO].osizes[octave]; 
  852.                     sample++)
  853.             {
  854.                 svx_info[C_DFLT_AUDIO].osamps[octave][sample] = 0;
  855.                 for (harmonic = 1;
  856.                      harmonic <= pow2( (double)octave);
  857.                      harmonic++)
  858.                 {
  859.                     svx_info[C_DFLT_AUDIO].osamps[octave][sample]
  860.                     += sin((2.0 * PI) * (double)harmonic
  861.                     * (double)sample
  862.                     / (double)(svx_info[C_DFLT_AUDIO].osizes[octave]))
  863.                     * 126.0 / harmonic;
  864.                 }
  865.             }
  866.         }
  867.         else
  868.         {
  869.             ; /* ran out of chip ram */
  870.         }
  871.         svx_info[C_DFLT_AUDIO].rsizes[octave]
  872.             = C_REPEAT_SAMP * (int)floor(pow2( (double)octave));
  873.         svx_info[C_DFLT_AUDIO].rsamps[octave]
  874.             = (BYTE *)AllocMem(svx_info[C_DFLT_AUDIO].rsizes[octave],
  875.             MEMF_CHIP | MEMF_PUBLIC);
  876.         if (svx_info[C_DFLT_AUDIO].rsamps[octave] != NULL)
  877.         {
  878.             memcpy( svx_info[C_DFLT_AUDIO].rsamps[octave],
  879.                     svx_info[C_DFLT_AUDIO].osamps[octave],
  880.                     svx_info[C_DFLT_AUDIO].osizes[octave]);
  881.         }
  882.         else
  883.         {
  884.             ; /* out of chip ram */
  885.         }
  886.         svx_info[C_DFLT_AUDIO].spcycs[octave] 
  887.             = C_ONESHOT_SAMP * (int)floor(pow2( (double)octave));
  888.     }
  889.     for (instrument = 0; instrument < C_DFLT_AUDIO; instrument++)
  890.     {
  891.         svx_info[instrument] = svx_info[C_DFLT_AUDIO];
  892.     }
  893.     return;
  894. }
  895.  
  896. static void de_init_audio_instruments(void)
  897. {
  898.     auto int    oct,
  899.                 chair;
  900.  
  901.     for (chair = 0; chair < C_DFLT_AUDIO; chair++)
  902.     {
  903.         if (svx_info[chair].rsamps[0] != svx_info[C_DFLT_AUDIO].rsamps[0])
  904.         {
  905.             for (oct = 0; oct < svx_info[chair].Vhdr.ctOctave; oct++)
  906.             {
  907.                 if (svx_info[chair].osamps[oct] != NULL)
  908.                 {   
  909.                     FreeMem(svx_info[chair].osamps[oct],
  910.                         svx_info[chair].osizes[oct]);
  911.                     svx_info[chair].osamps[oct] = NULL;
  912.                 }
  913.                 if (svx_info[chair].rsamps[oct] != NULL)
  914.                 {   
  915.                     FreeMem(svx_info[chair].rsamps[oct],
  916.                         svx_info[chair].rsizes[oct]);
  917.                     svx_info[chair].rsamps[oct] = NULL;
  918.                 }
  919.             }
  920.         }
  921.     }
  922.     /*
  923.     ** Free up the default voice
  924.     */
  925.     for (oct = 0; oct < C_TYP_OCTAVES; oct++)
  926.     {
  927.         if (svx_info[C_DFLT_AUDIO].osamps[oct] != NULL)
  928.         {   
  929.             FreeMem(svx_info[C_DFLT_AUDIO].osamps[oct],
  930.                 svx_info[C_DFLT_AUDIO].osizes[oct]);
  931.             svx_info[C_DFLT_AUDIO].osamps[oct] = NULL;
  932.         }
  933.         if (svx_info[C_DFLT_AUDIO].rsamps[oct] != NULL)
  934.         {   
  935.             FreeMem(svx_info[C_DFLT_AUDIO].rsamps[oct],
  936.                 svx_info[C_DFLT_AUDIO].rsizes[oct]);
  937.             svx_info[C_DFLT_AUDIO].rsamps[oct] = NULL;
  938.         }
  939.     }
  940.     return;
  941. }
  942.  
  943. int read_8svx(char *path_str, const int chair)
  944. {
  945.     auto unsigned char *body_buffer = NULL;
  946.     auto char *anno_buf = NULL;
  947.     static int  oneshot_index[MAXOCT],
  948.                 repeat_index[MAXOCT],
  949.                 true_len,
  950.                 octave,
  951.                 *channels,
  952.                 error;
  953.     static LONG chunk_list[C_CHUNKS_QTY * 2] 
  954.                 = {ID_8SVX, ID_VHDR, ID_8SVX, ID_NAME,
  955.                 ID_8SVX, ID_AUTH, ID_8SVX, ID_ATAK, ID_8SVX, ID_RLSE,
  956.                 ID_8SVX, ID_ANNO, ID_8SVX, ID_CHAN, ID_8SVX, ID_BODY};
  957.     auto struct IFFHandle *iff = NULL;
  958.     auto struct ContextNode     *body_node;
  959.     auto struct StoredProperty  *body_stored_property,
  960.                                 *vhdr_stored_property,
  961.                                 *anno_stored_property,
  962.                                 *name_stored_property,
  963.                                 *auth_stored_property,
  964.                                 *atak_stored_property,
  965.                                 *rlse_stored_property,
  966.                                 *chan_stored_property;
  967.     auto Voice8Header *voice_header;
  968.  
  969.     if(NULL == (iff = AllocIFF()))
  970.     {
  971.         /* AllocIFF() failed. */
  972.         /* goto bye */;
  973.     }
  974.     if (NULL == (iff->iff_Stream = Open(path_str, MODE_OLDFILE)))
  975.     {
  976.         FreeIFF(iff);
  977.         return 1;
  978.     }
  979.     InitIFFasDOS(iff);
  980.     if (error = OpenIFF(iff, IFFF_READ))
  981.     {
  982.         Close(iff->iff_Stream);
  983.         FreeIFF(iff);
  984.         /*failed*/;
  985.     }
  986.     error = PropChunks(iff, chunk_list, C_CHUNKS_QTY);
  987.     error = StopChunk(iff, ID_8SVX, ID_BODY);
  988.  
  989.     error = ParseIFF(iff, IFFPARSE_SCAN);
  990.     switch (error)
  991.     {
  992.         case IFFERR_EOF:
  993.             /* File scan complete. */
  994.             break;
  995.         case 0: /* found the body */
  996.             body_node = CurrentChunk(iff);
  997.             if (body_node != NULL)
  998.             {
  999.                 body_buffer = (unsigned char *)malloc(body_node->cn_Size);
  1000.                 if (body_buffer != NULL)
  1001.                 {
  1002.                     ReadChunkBytes(iff, body_buffer, body_node->cn_Size);
  1003.                 }
  1004.             }
  1005.             break;
  1006.         default:
  1007.             /* printf("File scan aborted, error %1d: %s\n",
  1008.                 error, errormsgs[-error - 1]); */
  1009.             break;
  1010.     }
  1011.     name_stored_property = FindProp(iff, ID_8SVX, ID_NAME);
  1012.     auth_stored_property = FindProp(iff, ID_8SVX, ID_AUTH);
  1013.     atak_stored_property = FindProp(iff, ID_8SVX, ID_ATAK);
  1014.     rlse_stored_property = FindProp(iff, ID_8SVX, ID_RLSE);
  1015.     chan_stored_property = FindProp(iff, ID_8SVX, ID_CHAN);
  1016.     if (chan_stored_property != NULL)
  1017.     {
  1018.         /* printf("chan len: %d\n", chan_stored_property->sp_Size); */
  1019.         channels = (int *)(chan_stored_property->sp_Data);
  1020.         switch (*channels)
  1021.         {
  1022.             case RIGHT:
  1023.                 /* RIGHT channel */
  1024.                 break;
  1025.             case LEFT:
  1026.                 /* LEFT channel */
  1027.                 break;
  1028.             case BOTH:
  1029.                 /* BOTH channels */
  1030.                 break;
  1031.             default:
  1032.                 break;
  1033.         }
  1034.     }
  1035.     vhdr_stored_property = FindProp(iff, ID_8SVX, ID_VHDR);
  1036.     if (vhdr_stored_property != NULL)
  1037.     {
  1038. /*        printf("vhdr len: %d\n", vhdr_stored_property->sp_Size); */
  1039.         voice_header = (Voice8Header *)(vhdr_stored_property->sp_Data);
  1040. /*                 printf("\toneShotHiSamples %d\n\trepeatHiSamples %d\n\
  1041. \tsamplesPerHiCycle %d\n\tsamplesPerSec %d\n\
  1042. \tctOctave %d\n\tsCompression %d\n\
  1043. \tvolume X%08X\n", voice_header->oneShotHiSamples, 
  1044.                 voice_header->repeatHiSamples, 
  1045.                 voice_header->samplesPerHiCycle, 
  1046.                 voice_header->samplesPerSec,
  1047.                 voice_header->ctOctave, voice_header->sCompression,
  1048.                 voice_header->volume); */
  1049.     }
  1050.     /* OK, this is the thing.
  1051.     ** If the instrument has no one shot,
  1052.     **  then don't try to play the one shot.
  1053.     ** If the instrument has no repeat
  1054.     ** then don't try to play the repeat part.
  1055.     ** If it has neither, don't load the instrument.
  1056.     */
  1057.     anno_stored_property = FindProp(iff, ID_8SVX, ID_ANNO);
  1058.     if (anno_stored_property != NULL)
  1059.     {
  1060.         /* printf("anno len: %d\n", anno_stored_property->sp_Size); */
  1061.         if (1 == (anno_stored_property->sp_Size % 2))
  1062.         {
  1063.             true_len = anno_stored_property->sp_Size + 2;
  1064.         }
  1065.         else
  1066.         {
  1067.             /* 
  1068.             ** need room for null 
  1069.             */
  1070.             true_len = anno_stored_property->sp_Size + 1;
  1071.         }
  1072.         anno_buf = malloc(true_len);
  1073.         if (anno_buf != NULL)
  1074.         {
  1075.             memcpy( anno_buf, anno_stored_property->sp_Data,
  1076.                     anno_stored_property->sp_Size);
  1077.             if (anno_stored_property->sp_Size >= 0)
  1078.             {   
  1079.                 anno_buf[anno_stored_property->sp_Size] = '\0';
  1080.                 free(anno_buf);
  1081.                 anno_buf = NULL;
  1082.             }
  1083.             else
  1084.             {
  1085.                 /* annotation size is negative */
  1086.             }
  1087.         }
  1088.     }
  1089.     body_stored_property = FindProp(iff, ID_8SVX, ID_BODY);
  1090.     /*
  1091.     ** compare the voice's first octave sample pointer to the default
  1092.     ** voice.  If they are the same, it is just a copy of the default
  1093.     ** voice.  If not, we must first de-allocate its loaded voice.
  1094.     */
  1095.     if (svx_info[chair].osamps[0] != svx_info[C_DFLT_AUDIO].osamps[0])
  1096.     {
  1097.         for (octave = 0; octave < svx_info[chair].Vhdr.ctOctave; octave++)
  1098.         {
  1099.             if (svx_info[chair].osamps[octave] != NULL)
  1100.             {   
  1101.                 FreeMem(svx_info[chair].osamps[octave],
  1102.                     svx_info[chair].osizes[octave]);
  1103.                 svx_info[chair].osamps[octave] = NULL;
  1104.             }
  1105.             if (svx_info[chair].rsamps[octave] != NULL)
  1106.             {   
  1107.                 FreeMem(svx_info[chair].rsamps[octave],
  1108.                     svx_info[chair].rsizes[octave]);
  1109.                 svx_info[chair].rsamps[octave] = NULL;
  1110.             }
  1111.         }
  1112.     }
  1113.     memset(&svx_info[chair], '\0', sizeof(struct EightSVXInfo));
  1114.     svx_info[chair].Vhdr = *voice_header;
  1115.     for (octave = 0;
  1116.         (octave < voice_header->ctOctave) && (octave < MAXOCT); 
  1117.         octave++)
  1118.     {
  1119.         oneshot_index[octave]
  1120.         = (voice_header->repeatHiSamples 
  1121.         + voice_header->oneShotHiSamples) 
  1122.         * ((int)floor(pow2((double)octave)) - 1);
  1123.         /*
  1124.         ** If there is a one shot part
  1125.         */
  1126.         if (voice_header->oneShotHiSamples > 0) 
  1127.         {
  1128.             svx_info[chair].osizes[octave] 
  1129.                 = voice_header->oneShotHiSamples 
  1130.                 * (int)floor(pow2((double)octave));
  1131.             svx_info[chair].osamps[octave] 
  1132.                 = (BYTE *)AllocMem(svx_info[chair].osizes[octave], 
  1133.                 MEMF_CHIP | MEMF_PUBLIC);
  1134.             if (svx_info[chair].osamps[octave] != NULL)
  1135.             {
  1136.                 memcpy(svx_info[chair].osamps[octave], 
  1137.                     &body_buffer[oneshot_index[octave]],
  1138.                     svx_info[chair].osizes[octave]);
  1139.             }
  1140.             else
  1141.             {
  1142.                 ; /* no more chip ram */
  1143.             }
  1144.         }
  1145.         /*
  1146.         ** If there is a repeat part
  1147.         */
  1148.         if (voice_header->repeatHiSamples > 0)
  1149.         {
  1150.             svx_info[chair].rsizes[octave]
  1151.                 = voice_header->repeatHiSamples 
  1152.                 * (int)floor(pow2((double)octave));
  1153.             repeat_index[octave]
  1154.                 = oneshot_index[octave] + svx_info[chair].osizes[octave];
  1155.             svx_info[chair].rsamps[octave]
  1156.                 = (BYTE *)AllocMem(svx_info[chair].rsizes[octave],
  1157.                 MEMF_CHIP | MEMF_PUBLIC);
  1158.             if (svx_info[chair].rsamps[octave] != NULL)
  1159.             {
  1160.                 memcpy(svx_info[chair].rsamps[octave], 
  1161.                     &body_buffer[repeat_index[octave]], 
  1162.                     svx_info[chair].rsizes[octave]);
  1163.             }
  1164.             else
  1165.             {
  1166.               /* out of chip ram */
  1167.             }
  1168.         }
  1169.         svx_info[chair].spcycs[octave] 
  1170.                 = voice_header->samplesPerHiCycle 
  1171.                 * (int)floor(pow2((double)octave));
  1172.     }
  1173.     if (body_buffer != NULL)
  1174.     {
  1175.         free(body_buffer);
  1176.         body_buffer = NULL;
  1177.     }
  1178.     if (anno_buf != NULL)
  1179.     {
  1180.         free(anno_buf);
  1181.         anno_buf = NULL;
  1182.     }
  1183.     strncpy(orch_str[chair], path_str, C_INST_NAME_LEN);
  1184. #ifndef CLI
  1185.     set_orch_gadgets(chair, path_str);
  1186. #endif
  1187.     CloseIFF(iff);
  1188.     Close(iff->iff_Stream);
  1189.     FreeIFF(iff);
  1190.     return 0;
  1191. }
  1192.  
  1193. #ifndef CLI
  1194.  
  1195. void open_orch_window(void)
  1196. {
  1197.     auto UWORD   topborder;
  1198.   
  1199.     if (orch_wind != NULL) 
  1200.     {
  1201.         return;
  1202.     }
  1203.     topborder   = main_screen->WBorTop 
  1204.                 + (main_screen->Font->ta_YSize + 1);
  1205.     if (NULL == create_orch_gadgets(topborder))
  1206.     {
  1207.         ;
  1208.     }
  1209.     else
  1210.     {
  1211.         if (NULL == (orch_wind = OpenWindowTags(NULL,
  1212.             WA_Title, "ORCHESTRA",
  1213.             WA_Left, 25L,
  1214.             WA_Gadgets, glist, WA_AutoAdjust, TRUE,
  1215.             WA_Width, 600, WA_MinWidth, 600,
  1216.             WA_InnerHeight, 176, WA_MinHeight, 186,
  1217.             WA_DragBar, TRUE, WA_DepthGadget, TRUE,
  1218.             WA_Activate, TRUE, 
  1219. #if 0       
  1220.             WA_CloseGadget, TRUE,
  1221. #endif
  1222.             WA_SmartRefresh, TRUE,
  1223.             WA_IDCMP, BUTTONIDCMP /* | IDCMP_CLOSEWINDOW */,
  1224.             WA_CustomScreen, main_screen, TAG_END)))
  1225.         {
  1226.              ;
  1227.         }
  1228.         else
  1229.         {
  1230.             GT_RefreshWindow(orch_wind, NULL);
  1231.             orch_mask = 1 << orch_wind->UserPort->mp_SigBit;
  1232.         }
  1233.     }
  1234.     return;
  1235. }
  1236.  
  1237. void close_orch(void)
  1238. {
  1239.     RemoveGList(orch_wind, glist, GAD_LAST);
  1240.     CloseWindowSafely(orch_wind);
  1241.     FreeGadgets(glist);
  1242.     glist = NULL;
  1243.     orch_wind = NULL;
  1244.     return;
  1245. }
  1246.  
  1247. static struct Gadget *create_orch_gadgets(UWORD topborder)
  1248. {
  1249.     auto struct NewGadget ng;
  1250.     auto struct Gadget *gad;
  1251.     auto int chair_ctr;
  1252.     static char label_str[16][16];
  1253.  
  1254.     gad = CreateContext(&glist);
  1255.     ng.ng_TextAttr = &font_choice;
  1256.     ng.ng_VisualInfo = vi;
  1257.     /*
  1258.     ** Set up Voice selection
  1259.     */
  1260.     ng.ng_Height = 11;
  1261.     for (chair_ctr = 0; chair_ctr < GAD_BUTTON_1; chair_ctr++)
  1262.     {
  1263.         ng.ng_Flags = NG_HIGHLABEL | PLACETEXT_LEFT;
  1264.         ng.ng_Width = 400;
  1265.         ng.ng_LeftEdge = 90;
  1266.         ng.ng_GadgetText = NULL;
  1267.         ng.ng_TopEdge = 11 + (11 * chair_ctr);
  1268.         ng.ng_GadgetID = chair_ctr;
  1269.         strncpy(orch_str[chair_ctr], T_DFLT_NAME, C_INST_NAME_LEN);
  1270.         orch_str[chair_ctr][C_INST_NAME_LEN - 1] = '\0';
  1271.         orch_gads[chair_ctr] 
  1272.             = gad
  1273.             = CreateGadget(TEXT_KIND, gad, &ng, GTTX_Text, 
  1274.                 orch_str[chair_ctr], TAG_END, 0L); 
  1275.         /*
  1276.         ** Set up buttons
  1277.         */
  1278.         ng.ng_Width = 85;
  1279.         ng.ng_LeftEdge = 1;
  1280.         sprintf(label_str[chair_ctr], "Chair %2d:", chair_ctr + 1);
  1281.         ng.ng_GadgetText = label_str[chair_ctr];
  1282.  
  1283.         ng.ng_Flags = 0L;
  1284.         ng.ng_GadgetID = GAD_BUTTON_1 + chair_ctr;
  1285.         orch_gads[chair_ctr + GAD_BUTTON_1]
  1286.             = gad
  1287.             = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END, 0L);
  1288.     }
  1289.     return gad;
  1290. }
  1291.  
  1292. void set_orch_gadgets(int chair, char *instrument_name)
  1293. {
  1294.     auto char temp_instr_name[C_INST_NAME_LEN];
  1295.     strncpy(temp_instr_name, instrument_name, C_INST_NAME_LEN);
  1296.     temp_instr_name[C_INST_NAME_LEN - 1] = '\0';
  1297.     GT_SetGadgetAttrs(orch_gads[chair], orch_wind, NULL, 
  1298.         GTTX_Text, temp_instr_name, TAG_END, 0L);
  1299.     
  1300.     return;
  1301. }
  1302.  
  1303. #endif
  1304.  
  1305. int process_audio_events(void)
  1306. {
  1307.     static char instr_path[64] = "\0",
  1308.                 instr_file[64] = "\0", 
  1309.                 instr_dir[64] = "\0",
  1310.                 instr_banner[] = "Load IFF/8SVX file";
  1311.     auto int result = 0,
  1312.              asl_result,
  1313.              sts,
  1314.              Closing = FALSE;
  1315.     auto ULONG imsgClass;
  1316.     auto UWORD imsgCode;
  1317.     auto struct Gadget *gad;
  1318.     auto struct IntuiMessage *imsg;
  1319.     static struct FileRequester *asl_request;
  1320.     static struct TagItem asl_tags[8] =
  1321.         {{ASL_Dir,     NULL}, {ASL_File,     NULL}, {ASL_Hail,     NULL},
  1322.         {ASL_Window,   NULL}, {ASL_LeftEdge, 320},   {ASL_TopEdge,  10},
  1323.         {ASL_Height,  180}, {TAG_DONE,     NULL}};
  1324.     
  1325.     while (imsg = GT_GetIMsg(orch_wind->UserPort))
  1326.     {
  1327.         gad = (struct Gadget *)imsg->IAddress;
  1328.         imsgClass = imsg->Class;
  1329.         imsgCode = imsg->Code;
  1330.         GT_ReplyIMsg(imsg);
  1331.         switch(imsgClass)
  1332.         {
  1333.             case IDCMP_CLOSEWINDOW:
  1334.                 Closing = TRUE;
  1335.                 break;
  1336.             case IDCMP_GADGETUP:
  1337.                 asl_tags[0].ti_Data = (ULONG)instr_dir;
  1338.                 asl_tags[1].ti_Data = (ULONG)instr_file;
  1339.                 asl_tags[2].ti_Data = (ULONG)instr_banner;
  1340.                 asl_tags[3].ti_Data = (ULONG)orch_wind;
  1341.                 asl_request = AllocAslRequest(ASL_FileRequest, asl_tags);
  1342.                 asl_result = AslRequest(asl_request, NULL);
  1343.                 if (NULL == asl_result)
  1344.                 {
  1345.                     DisplayBeep(NULL);
  1346.                 }
  1347.                 else
  1348.                 {
  1349.                     strcpy(instr_dir, asl_request->rf_Dir);
  1350.                     strcpy(instr_file, asl_request->rf_File);
  1351.                     strcpy(instr_path, asl_request->rf_Dir);
  1352.                     if ((instr_path[strlen(instr_path)- 1] != ':')
  1353.                       && (strlen(instr_path) != 0))
  1354.                     {
  1355.                         strcat(instr_path, "/");
  1356.                     }
  1357.                     strcat(instr_path, asl_request->rf_File);
  1358.                     sts = read_8svx(instr_path, gad->GadgetID 
  1359.                         - GAD_BUTTON_1);
  1360.                     if (sts)
  1361.                     {
  1362.                         DisplayBeep(NULL);
  1363.                     }
  1364.                 }
  1365.                 result = 1;
  1366.                 FreeAslRequest(asl_request);
  1367.                 break;
  1368.             default:
  1369.                 break;
  1370.         }
  1371.     }
  1372.     if (Closing)
  1373.     {
  1374. #ifndef CLI
  1375.         close_orch();
  1376. #endif
  1377.     }
  1378.     return result;
  1379. }
  1380.  
  1381. void fprint_orch(FILE * file)
  1382. {
  1383.     auto int ctr;
  1384.     for (ctr = 0; ctr < (C_INSTR_QTY - 1); ctr++)
  1385.     {
  1386.         if (strcmp(orch_str[ctr], T_DFLT_NAME) != 0)
  1387.         {
  1388.             fprintf(file, "%2d %s\n", ctr, orch_str[ctr]);
  1389.         }
  1390.     }
  1391.     return;
  1392. }
  1393.